//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace WorkflowApplication
{
    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Xml;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Research.ScientificWorkflow.UIDesigner;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.Monitor;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Practices.Unity;
    using WorkflowApplication.Interfaces;
    using WorkflowApplicationControls;
    using WorkflowApplicationModels;
    using WorkflowApplicationModels.Helpers;
    using WorkflowApplicationServices;
    using SR = Microsoft.Research.DataLayer;
    using System.Windows.Threading;
    using Microsoft.Research.DataLayer;
    using System.Globalization;
    using System.Security;

    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class WorkflowApp : Window, IRegionManager, IDisposable
    {
        #region Private Data

        /// <summary>
        /// The connection manager.
        /// </summary>
        private SR.ConnectionManager connMgr;

        /// <summary>
        /// The registry connection.
        /// </summary>
        private SR.Connection registryConnection;

        /// <summary>
        /// The Unity container instance used for dependency injection.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// The center pane controller.
        /// </summary>
        private CenterPaneController centerPaneHandler;

        /// <summary>
        /// The presenter for the left pane.
        /// </summary>
        private ILeftPanePresenter leftPanePresenter;

        /// <summary>
        /// The presenter for the toolbar.
        /// </summary>
        private ToolBarPresenter toolBarPresenter;

        /// <summary>
        /// The mode in which the app is running.
        /// </summary>
        private WorkflowAppMode appMode;

        /// <summary>
        /// The polling connection.
        /// </summary>
        private SR.Connection pollingConnection;

        /// <summary>
        /// Registry service.
        /// </summary>
        private RegistryService regSvc;

        #endregion Private Data

        #region Public Properties

        /// <summary>
        /// Gets or sets the current app mode.
        /// </summary>
        /// <value>The current app mode.</value>
        public WorkflowAppMode CurrentAppMode
        {
            get
            {
                return this.appMode;
            }
            set
            {
                this.appMode = value;
            }
        }

        /// <summary>
        /// Gets or sets the current WFL file path.
        /// </summary>
        /// <value>The current WFL file path.</value>
        public string CurrentWflFilePath
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the current wfmodel.
        /// </summary>
        public WorkflowModel CurrentWfModel
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the registry connection.
        /// </summary>
        /// <value>The registry connection.</value>
        public SR.Connection RegistryConnection
        {
            get
            {
                return this.registryConnection;
            }
            set
            {
                this.registryConnection = value;
                if (this.regSvc != null)
                {
                    this.regSvc.CurrentConnection = this.RegistryConnection;
                }

                if (this.RegistryConnection != null)
                {
                    this.PollingConnection = this.RegistryConnection.Clone();
                    this.PollingConnection.Open();
                }
                else
                {
                    this.PollingConnection = null;
                }
            }
        }

        /// <summary>
        /// Gets or sets the polling connection.
        /// </summary>
        /// <value>The polling connection.</value>
        public SR.Connection PollingConnection
        {
            get
            {
                return this.pollingConnection;
            }
            set
            {
                this.pollingConnection = value;
                if (this.container != null)
                {
                    IDataProductService dataProductSvc = this.container.Resolve<IDataProductService>();
                    if (dataProductSvc != null)
                    {
                        dataProductSvc.PollingConnection = this.PollingConnection;
                    }
                }
            }
        }

        #endregion Public Properties

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkflowApp"/> class.
        /// </summary>
        public WorkflowApp()
        {
            InitializeComponent();
            this.CurrentAppMode = WorkflowAppMode.Normal;
            if (Application.Current.Properties.Contains(WflFileHelper.WflFilePath))
            {
                this.CurrentAppMode = WorkflowAppMode.Standalone;
                this.CurrentWflFilePath = Application.Current.Properties[WflFileHelper.WflFilePath].ToString();
            }

            this.Dispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(this.OnUnhandledException);
            this.Loaded += new RoutedEventHandler(this.OnWorkflowAppLoaded);
            this.Closing += new CancelEventHandler(this.OnWorkflowAppClosing);
        }

        #endregion Constructor

        #region Private Methods

        /// <summary>
        /// This is handled essentially for preventing app crashes and doing appropriate logging.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">DispatcherUnhandledExceptionEventArgs</param>
        private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            TridentErrorHandler.HandleKnownExceptionsInUI(this, e.Exception);
            if (e.Exception != null && (e.Exception is BackendStorageException || e.Exception.InnerException is BackendStorageException))
            {
                e.Handled = true;
            }
        }

        /// <summary>
        /// Called when loaded.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void OnWorkflowAppLoaded(object sender, RoutedEventArgs e)
        {
            this.InitializeRegistry();
            this.InitializeConnection();

            this.InitializeContainer();
            this.InitializeServices();
            this.InitializeModules();
        }

        /// <summary>
        /// Called when closing of the window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
        private void OnWorkflowAppClosing(object sender, CancelEventArgs e)
        {
            if (this.centerPaneHandler != null && this.centerPaneHandler.ExecutionMode)
            {
                MessageBoxResult result = TridentMessageBox.ShowTridentConfirmationYesNoCancelMessageBox(
                    WorkflowApplicationResourceManager.GetString("ExitConfirmation"));
                switch (result)
                {
                    case MessageBoxResult.Yes:
                        // Abort the job and close the app.
                        this.centerPaneHandler.TerminateJob();
                        break;

                    case MessageBoxResult.No:
                        // Do not abort the job, but close the application.
                        break;

                    case MessageBoxResult.Cancel:
                        // Cancel application close.
                        e.Cancel = true;
                        break;
                }
            }
        }

        /// <summary>
        /// Initializes the registry.
        /// </summary>
        private void InitializeRegistry()
        {
            try
            {
                // Initialize Connection.
                SR.SR_Connection.Init();
                connMgr = SR.ConnectionManager.Create(SR.ConnectionManager.CancelBehavior.ThrowException);
                connMgr.UIStyle = SR.ConnectionManagerBase.UIStyleType.Lite;
            }
            catch (Microsoft.Research.DataLayer.ConnectionFailure connectionFailure)
            {
                TridentErrorHandler.HandleUIException(connectionFailure);
                TridentMessageBox.ShowTridentErrorMessageBox(connectionFailure.InnerException.Message);
                Environment.Exit(0);
            }
            catch (InvalidOperationException exception)
            {
                TridentErrorHandler.HandleUIException(exception);
                TridentMessageBox.ShowTridentErrorMessageBox(exception.Message);
                Environment.Exit(0);
            }
            catch (Exception exception)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(exception);
                Environment.Exit(0);
            }
        }

        /// <summary>
        /// Initialize the registry connection.
        /// </summary>
        private void InitializeConnection()
        {
            bool isValid;

            SR.BackendStorageException connFailure;
            if (connMgr.HasDefaultConnection && !connMgr.TestConnection(connMgr.DefaultConnection, out connFailure))
            {
                TridentMessageBox.ShowTridentErrorMessageBox(connFailure.InnerException.Message);
                isValid = false;
            }
            else
            {
                isValid = true;
            }

            do
            {
                try
                {
                    if (!isValid)
                    {
                        this.RegistryConnection = connMgr.PickConnection(SR.ConnectionManager.ConnectionUI.AlwaysShowUI);
                    }
                    else
                    {
                        this.RegistryConnection = connMgr.PickConnection(SR.ConnectionManager.ConnectionUI.PromptIfNeeded);
                    }

                    if (null != this.RegistryConnection)
                    {
                        if (!Helper.IsValidConnection(this.RegistryConnection))
                        {
                            TridentMessageBox.ShowTridentErrorMessageBox(
                                TridentCommonResourceManager.GetString("InvalidRegistryConnection"));
                            isValid = false;
                            continue;
                        }

                        this.RegistryConnection.AutoSave = false;
                        this.AuthenticateUser();
                    }

                    isValid = true;
                }
                catch (SR.ConnectionFailure connectionFailure)
                {
                    TridentErrorHandler.HandleUIException(connectionFailure);
                    TridentMessageBox.ShowTridentErrorMessageBox(connectionFailure.InnerException.Message);
                    isValid = false;
                }
                catch (InvalidOperationException exception)
                {
                    TridentErrorHandler.HandleUIException(exception);
                    TridentMessageBox.ShowTridentErrorMessageBox(exception.Message);
                    isValid = false;
                }
                catch (TridentCustomException customExp)
                {
                    TridentErrorHandler.HandleTridentCustomExceptionInUI(customExp, false);
                    isValid = false;
                }
                catch (Exception exception)
                {
                    TridentErrorHandler.HandleKnownExceptionsInUI(exception, false);
                    isValid = false;
                }
            } while (!isValid);

            if (null == this.RegistryConnection)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(
                    TridentCommonResourceManager.GetString("RegistryNotSelected"));
                Environment.Exit(0);
            }
        }

        /// <summary>
        /// Initializes the services.
        /// </summary>
        private void InitializeServices()
        {
            this.regSvc = new RegistryService(this.RegistryConnection);
            this.container.RegisterInstance<IRegistryService>(this.regSvc);
            IDataProductService dataProductSvc = new DataProductService();
            dataProductSvc.ClearTempData();
            dataProductSvc.PollingConnection = this.PollingConnection;
            this.container.RegisterInstance<IDataProductService>(dataProductSvc);
        }

        /// <summary>
        /// Initializes the unity container.
        /// </summary>
        private void InitializeContainer()
        {
            this.container = new UnityContainer();
            this.container.RegisterInstance<IUnityContainer>(this.container, new ExternallyControlledLifetimeManager());
            this.container.RegisterInstance<IRegionManager>("MainWindow", this, new ExternallyControlledLifetimeManager());
            this.container.RegisterInstance(typeof(SR.Connection), this.RegistryConnection, new ExternallyControlledLifetimeManager());
            this.container.RegisterInstance<IStatusMessageControl>(this.StatusControl, new ExternallyControlledLifetimeManager());
        }

        /// <summary>
        /// Initializes the modules.
        /// </summary>
        private void InitializeModules()
        {
            try
            {
                DataProductIconBuilder.Initialize();
                DataProductIconBuilder.ExtractIcons();
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }

            this.toolBarPresenter = this.container.Resolve<ToolBarPresenter>();
            this.container.RegisterInstance<ToolBarPresenter>("ToolbarPresenter", this.toolBarPresenter, new ExternallyControlledLifetimeManager());
            this.toolBarPresenter.SaveAsWorkflowLinkCommand = new DelegateCommand<object>(p => this.OnSaveAsWfl(), p => this.OnSaveAsWflCanExecute());
            this.toolBarPresenter.ExitCommand = new DelegateCommand<object>(p => this.OnExitRequest());
            this.toolBarPresenter.SavedConnectionCommand = new DelegateCommand<object>(p => this.SavedConnectionCommandExecute(), p => this.SavedConnectionCanExecute());
            this.toolBarPresenter.AdvancedConnectionCommand = new DelegateCommand<object>(p => this.AdvancedConnectionCommandExecute(), p => this.AdvancedConnectionCanExecute());
            this.toolBarPresenter.AboutCommand = new DelegateCommand<object>(p => this.AboutBoxCommandExecute());
            this.toolBarPresenter.RefreshCommand = new DelegateCommand<object>(p => this.RefreshCommandExecute(), p => this.RefreshCommandCanExecute());
            if (this.toolBarPresenter != null)
            {
                this.Add(this.toolBarPresenter.ContentView, "toolBarGrd");
            }

            this.centerPaneHandler = this.container.Resolve<CenterPaneController>();
            this.centerPaneHandler.RequestCanExecuteCheck += new EventHandler(delegate(object sender, EventArgs e) { this.RaiseCanExecute(); });
            this.centerPaneHandler.Initialize();
            if (this.centerPaneHandler != null)
            {
                this.Add(this.centerPaneHandler.View, "centerPaneHolder");
            }

            if (this.CurrentAppMode == WorkflowAppMode.Standalone)
            {
                this.OpenWflFile();
                this.leftPaneColDefn.MinWidth = 0;
                this.leftPaneColDefn.Width = new GridLength(0);
                this.lftPaneSplitter.Visibility = Visibility.Collapsed;
                this.toolBarPresenter.ShowSaveAsWorkflowLink = false;
                this.toolBarPresenter.ShowConnectionOptions = false;
            }
            else
            {
                this.toolBarPresenter.ShowSaveAsWorkflowLink = true;
                this.toolBarPresenter.ShowConnectionOptions = true;
                this.leftPanePresenter = this.container.Resolve<LeftPanePresenter>();
                if (this.leftPanePresenter != null)
                {
                    this.leftPanePresenter.ItemSelectedCommand = new WorkflowAppCommand<BaseModel>(this.OnItemSelectedExecute);
                    this.leftPanePresenter.Initialize();
                    this.Add(this.leftPanePresenter.LeftPane, "leftPaneHost");
                }
            }
        }

        /// <summary>
        /// Refreshes the workflows tree.
        /// </summary>
        private void RefreshCommandExecute()
        {
            try
            {
                if (this.CurrentAppMode == WorkflowAppMode.Normal)
                {
                    // Refresh the system policy object to take care of any changes in the role of the user.
                    Helper.RefreshSystemPolicy(this.RegistryConnection);

                    // Post refresh, if the current workflow is no more present in the registry, clear the center pane.
                    if (!this.leftPanePresenter.Refresh(this.CurrentWfModel))
                    {
                        this.CurrentWfModel = null;
                        this.SetTitle(string.Empty);
                        this.centerPaneHandler.ClearRunWindow();
                    }
                }
                else
                {
                    this.CurrentWfModel = null;
                    this.SetTitle(string.Empty);
                    this.centerPaneHandler.ClearRunWindow();
                    this.OpenWflFile();
                }

                this.RaiseCanExecute();
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);
            }
        }

        /// <summary>
        /// Saved connection can execute.
        /// </summary>
        /// <returns></returns>
        private bool SavedConnectionCanExecute()
        {
            return !this.centerPaneHandler.ExecutionMode;
        }

        /// <summary>
        /// Advanced connection can execute.
        /// </summary>
        /// <returns></returns>
        private bool AdvancedConnectionCanExecute()
        {
            return !this.centerPaneHandler.ExecutionMode;
        }

        /// <summary>
        /// Refresh command can execute.
        /// </summary>
        /// <returns></returns>
        private bool RefreshCommandCanExecute()
        {
            return !this.centerPaneHandler.ExecutionMode;
        }

        /// <summary>
        /// Handles request for app close.
        /// </summary>
        private void OnExitRequest()
        {
            this.Close();
        }

        /// <summary>
        /// Invokes all the can execute requests.
        /// </summary>
        private void RaiseCanExecute()
        {
            this.toolBarPresenter.SaveAsWorkflowLinkCommand.RaiseCanExecuteChanged();
            this.toolBarPresenter.SavedConnectionCommand.RaiseCanExecuteChanged();
            this.toolBarPresenter.AdvancedConnectionCommand.RaiseCanExecuteChanged();
            this.toolBarPresenter.RefreshCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Checks if the SaveAsWfl command can be enabled or not.
        /// </summary>
        /// <returns></returns>
        private bool OnSaveAsWflCanExecute()
        {
            return (this.CurrentWfModel != null);
        }

        /// <summary>
        /// Opens the workflow represented by the current wfl path.
        /// </summary>
        private void OpenWflFile()
        {
            StringBuilder errorBuilder = new StringBuilder(WorkflowApplicationResourceManager.GetString("WflOpenError"));
            try
            {
                if (!string.IsNullOrEmpty(this.CurrentWflFilePath) && File.Exists(this.CurrentWflFilePath))
                {
                    XmlNode dataNode = null;
                    using (FileStream fStream = new FileStream(this.CurrentWflFilePath, FileMode.Open))
                    {
                        using (BinaryReader bReader = new BinaryReader(fStream))
                        {
                            XmlDocument xmlDocument = new XmlDocument();
                            byte[] txtByte64 = System.Convert.FromBase64String(bReader.ReadString());
                            string txt = System.Text.Encoding.Default.GetString(txtByte64);
                            xmlDocument.LoadXml(txt);

                            StringBuilder xPathBuilder = new StringBuilder("/");
                            xPathBuilder.Append(WflFileHelper.WorkflowRootNode);
                            xPathBuilder.Append("/");
                            xPathBuilder.Append(WflFileHelper.WorkflowIdNode);
                            dataNode = xmlDocument.SelectSingleNode(xPathBuilder.ToString());
                        }
                    }

                    if (dataNode != null)
                    {
                        string guidData = dataNode.InnerText;
                        if (!string.IsNullOrEmpty(guidData))
                        {
                            this.OpenWflFileById(new Guid(guidData));
                        }
                    }
                }
                else
                {
                    StringBuilder appCloseMsg = new StringBuilder(WorkflowApplicationResourceManager.GetString("WflFileInvalidOrAbsent"));
                    appCloseMsg.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                    TridentMessageBox.ShowTridentErrorMessageBox(appCloseMsg.ToString());
                    Environment.Exit(0);
                }
            }
            catch (XmlException ex)
            {
                // TridentErrorHandler.HandleUIException(ex);
                errorBuilder.Append(ex.Message);
                errorBuilder.Append(" ");
                errorBuilder.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                TridentMessageBox.ShowTridentErrorMessageBox(errorBuilder.ToString());
                Environment.Exit(0);
            }
            catch (IOException ex)
            {
                // TridentErrorHandler.HandleUIException(ex);
                errorBuilder.Append(ex.Message);
                errorBuilder.Append(" ");
                errorBuilder.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                TridentMessageBox.ShowTridentErrorMessageBox(errorBuilder.ToString());
                Environment.Exit(0);
            }
            catch (FormatException ex)
            {
                // TridentErrorHandler.HandleUIException(ex);
                errorBuilder.Append(ex.Message);
                errorBuilder.Append(" ");
                errorBuilder.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                TridentMessageBox.ShowTridentErrorMessageBox(errorBuilder.ToString());
                Environment.Exit(0);
            }
            catch (OverflowException ex)
            {
                // TridentErrorHandler.HandleUIException(ex);
                errorBuilder.Append(ex.Message);
                errorBuilder.Append(" ");
                errorBuilder.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                TridentMessageBox.ShowTridentErrorMessageBox(errorBuilder.ToString());
                Environment.Exit(0);
            }
            catch (Exception ex)
            {
                // TridentErrorHandler.HandleUIException(ex);
                errorBuilder.Append(ex.Message);
                errorBuilder.Append(" ");
                errorBuilder.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                TridentMessageBox.ShowTridentErrorMessageBox(errorBuilder.ToString());
                Environment.Exit(0);
            }
        }

        /// <summary>
        /// Opens the passed wfl file based on the id.
        /// </summary>
        /// <param name="wflFileId">
        /// The wfl file id.
        /// </param>
        private void OpenWflFileById(Guid wflFileId)
        {
            bool retry = true;
            while (retry)
            {
                try
                {
                    retry = !this.OpenWorkflow(wflFileId, true);
                }
                catch (TridentCustomException ex)
                {
                    if (ex != null)
                    {
                        StringBuilder errorMsgBuilder = new StringBuilder(ex.Message);
                        if (ex.ErrorNumber.Equals(TridentErrorConstants.ErrorNumber1000000011.ToString(CultureInfo.CurrentCulture))
                            || (ex.InnerException != null && ex.InnerException is SecurityException))
                        {
                            errorMsgBuilder.Append(Environment.NewLine);
                            errorMsgBuilder.Append(WorkflowApplicationResourceManager.GetString("ApplicationClose"));
                            ex = new TridentCustomException(errorMsgBuilder.ToString());
                            TridentErrorHandler.HandleKnownExceptionsInUI(ex);
                            this.Close();
                            Environment.Exit(0);
                        }
                        else
                        {
                            retry = true;
                        }
                    }
                }

                if (retry)
                {
                    if (MessageBoxResult.Yes == TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(
                        WorkflowApplicationResourceManager.GetString("WorkflowNotFound")))
                    {
                        // Bring up the connection manager in the loop.
                        this.connMgr.UIStyle = SR.ConnectionManagerBase.UIStyleType.Lite;
                        SR.Connection conn = connMgr.PickConnection(SR.ConnectionManager.ConnectionUI.AlwaysShowUI);
                        if (conn != null && conn.Alive)
                        {
                            this.RegistryConnection = conn;
                            this.RegistryConnection.AutoSave = false;
                        }
                    }
                    else
                    {
                        retry = false;
                        this.Close();
                        Environment.Exit(0);
                    }
                }
                else
                {
                    if (this.centerPaneHandler != null && this.centerPaneHandler.CurrentWorkflowModel != null)
                    {
                        this.SetTitle(this.centerPaneHandler.CurrentWorkflowModel.Name);
                    }
                }
            }
        }

        /// <summary>
        /// Called when item selected.
        /// </summary>
        /// <param name="model">The model.</param>
        private void OnItemSelectedExecute(BaseModel model)
        {
            if (model != null)
            {
                WorkflowModel wfModel = model as WorkflowModel;
                if (wfModel != null)
                {
                    if (this.OpenWorkflow(wfModel.Id, false))
                    {
                        this.SetTitle(wfModel.Label);
                        this.CurrentWfModel = wfModel;
                    }
                    else
                    {
                        this.CurrentWfModel = null;
                        this.SetTitle(string.Empty);
                        this.centerPaneHandler.ClearRunWindow();
                    }

                    this.RaiseCanExecute();
                }
            }

            this.StatusControl.SetText(string.Empty);
        }

        /// <summary>
        /// Opens the workflow based on the workflow id.
        /// </summary>
        /// <param name="workflowId">
        /// The workflow id.
        /// </param>
        private bool OpenWorkflow(Guid workflowId, bool throwOnError)
        {
            bool openSuccess = true;
            try
            {
                if (workflowId != Guid.Empty)
                {
                    this.centerPaneHandler.WorkflowId = workflowId;
                }
            }
            catch (TridentCustomException ex)
            {
                if (throwOnError)
                {
                    throw ex;
                }

                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
                openSuccess = false;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);
                openSuccess = false;
            }

            return openSuccess;
        }

        /// <summary>
        /// Called when user requests a Save as WFL.
        /// </summary>
        private void OnSaveAsWfl()
        {
            if (this.centerPaneHandler.CurrentWorkflowModel != null)
            {
                bool validSave = true;
                try
                {
                    SR.Activity wfToSave = SR.Activity.Load(this.centerPaneHandler.WorkflowId, this.RegistryConnection);
                    if (null == wfToSave || wfToSave.IsDeleted)
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(
                            this,
                            WorkflowApplicationResourceManager.GetString("SaveAsWflDeleted"));
                        validSave = false;
                    }
                }
                catch (RecordNotFoundException)
                {
                    validSave = false;
                    //Do not do anything, save will fail, and appropriate message will be displayed.
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.HandleKnownExceptionsInUI(ex);
                    validSave = false;
                    //Do not do anything, save will fail, and appropriate message will be displayed.
                }

                if (validSave && WflFileHelper.SaveAsWfl(this.centerPaneHandler.WorkflowId))
                {
                    this.StatusControl.SetText(WorkflowApplicationResourceManager.GetString("WflFileSaved"));
                }
            }
        }

        /// <summary>
        /// Open Lite connection Manager Dialog.
        /// </summary>
        private void SavedConnectionCommandExecute()
        {
            this.connMgr.UIStyle = SR.ConnectionManagerBase.UIStyleType.Lite;
            this.AssignConnection();
        }

        /// <summary>
        /// Handles the advanced connection request.
        /// </summary>
        private void AdvancedConnectionCommandExecute()
        {
            this.connMgr.UIStyle = SR.ConnectionManagerBase.UIStyleType.Normal;
            this.AssignConnection();
        }

        /// <summary>
        /// Brings up the connection manager based on the current set UIStyle.
        /// </summary>
        private void AssignConnection()
        {
            try
            {
                if (this.ReInitializeConnection())
                {
                    this.RefreshWorkflowApp();
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);
            }
        }

        /// <summary>
        /// ReInitialize connection.
        /// </summary>
        /// <returns>
        /// True if Connection successfully created, False otherwise.
        /// </returns>
        private bool ReInitializeConnection()
        {
            bool isValid;
            bool connectionChanged = false;
            do
            {
                try
                {
                    SR.Connection conn = connMgr.PickConnection(SR.ConnectionManager.ConnectionUI.AlwaysShowUI);
                    if (conn != null && conn.Alive)
                    {
                        if (!Helper.IsValidConnection(conn))
                        {
                            TridentMessageBox.ShowTridentErrorMessageBox(
                                TridentCommonResourceManager.GetString("InvalidRegistryConnection"));
                            isValid = false;
                            continue;
                        }

                        connectionChanged = true;
                        this.RegistryConnection = conn;

                        // Disable AutoSave.
                        this.RegistryConnection.AutoSave = false;

                        // Authenticate user in the new connection.
                        this.AuthenticateUser();

                        // Resets the system policy.
                        SystemPolicy.Reset();
                    }

                    isValid = true;
                }
                catch (SR.ConnectionFailure connectionFailure)
                {
                    TridentErrorHandler.HandleUIException(connectionFailure);
                    TridentMessageBox.ShowTridentErrorMessageBox(connectionFailure.InnerException.Message);
                    isValid = false;
                }
                catch (TridentCustomException customExp)
                {
                    TridentErrorHandler.HandleTridentCustomExceptionInUI(customExp, false);
                    isValid = false;
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.HandleKnownExceptionsInUI(ex, false);
                    isValid = false;
                }
            } while (!isValid);

            return connectionChanged;
        }

        /// <summary>
        /// Authenticates the user.
        /// </summary>
        private void AuthenticateUser()
        {
            TridentAuthentication authendicate = new TridentAuthentication(this.RegistryConnection);
            authendicate.AuthenticateUser();
        }

        /// <summary>
        /// Refresh the workflow application on connection change.
        /// </summary>
        private void RefreshWorkflowApp()
        {
            this.container.Dispose();
            this.ClearRegionManager();
            this.StatusControl.SetText(string.Empty);
            this.CurrentWfModel = null;
            this.SetTitle(string.Empty);

            this.InitializeContainer();
            this.InitializeServices();
            this.InitializeModules();
            this.RaiseCanExecute();
        }

        /// <summary>
        /// Clear the region manager of the UI elements added by modules.
        /// </summary>
        private void ClearRegionManager()
        {
            this.ClearRegion("leftPaneHost");
            this.ClearRegion("centerPaneHolder");
            this.ClearRegion("toolBarGrd");
        }

        /// <summary>
        /// Clear the required region.
        /// </summary>
        /// <param name="regionName">The region to be cleared.</param>
        private void ClearRegion(string regionName)
        {
            Panel region = this.FindName(regionName) as Panel;
            if (region != null)
            {
                region.Children.Clear();
            }
        }

        /// <summary>
        /// Brings up the about box.
        /// </summary>
        private void AboutBoxCommandExecute()
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.Owner = Application.Current.MainWindow;
            aboutBox.ShowDialog();
        }

        #endregion Private Methods

        #region IRegionManager Members

        /// <summary>
        /// Add the UI element into the region specified.
        /// </summary>
        /// <param name="view">The UI element to be added.</param>
        /// <param name="regionName">The region name.</param>
        public void Add(object view, string regionName)
        {
            Panel region = this.FindName(regionName) as Panel;
            if (region != null)
            {
                region.Children.Add(view as UIElement);
            }
        }

        /// <summary>
        /// Sets the title.
        /// </summary>
        /// <param name="title">The title.</param>
        public void SetTitle(string title)
        {
            if (!string.IsNullOrEmpty(title) && !string.IsNullOrEmpty(title.Trim()))
            {
                StringBuilder titleBuilder = new StringBuilder(title);
                titleBuilder.Append(" - ");
                titleBuilder.Append(WorkflowApplicationResourceManager.GetString("Title"));
                this.Title = titleBuilder.ToString();
            }
            else
            {
                this.Title = WorkflowApplicationResourceManager.GetString("Title");
            }
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Operation to perform while Disposing the object.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// nullify and Disposes the object 
        /// </summary>
        /// <param name="disposing"></param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.container.Dispose();
            }
        }

        #endregion
    }

    /// <summary>
    /// Indicates if the app has been opened in normal mode or by double clicking on the wfl file.
    /// </summary>
    public enum WorkflowAppMode
    {
        /// <summary>
        /// Regular mode, with access to all workflows.
        /// </summary>
        Normal,

        /// <summary>
        /// Opened only for the wfl file, will not display the workflow tree.
        /// </summary>
        Standalone
    }
}
